package com.dl.test.interceptor;

import com.dl.test.util.ExecutorPluginUtils;
import com.dl.test.util.SqlUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.util.TablesNamesFinder;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Properties;

/**
 * 自定义mybatis拦截器
 * @author DL
 * @create 2022-08-26 19:15
 */
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
@Component
public class MybatisInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        String initialSql = ExecutorPluginUtils.getSqlByInvocation(invocation);
        log.info("sql替换前：{}", initialSql);
        // 执行自定义修改sql操作
        // 获取sql
        String newSql = "";
        //忽略sql中包含on conflict的情况
        Statement statement = CCJSqlParserUtil.parse(initialSql);


        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        log.info("mappedStatement:{}", mappedStatement.toString());
        Configuration configuration = mappedStatement.getConfiguration();
        log.info("configuration:{}", configuration);

        TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
        List<String> tableList = tablesNamesFinder.getTableList(statement);
        log.info("tableList:{}", tableList);

        try {
            if (statement instanceof Select) {
                Select selectStatement = (Select) statement;

                PlainSelect plain = (PlainSelect) selectStatement.getSelectBody();
                log.info("plain:{}", plain);

                FromItem fromItem = plain.getFromItem();
                log.info("fromItem:{}", fromItem);

                newSql = SqlUtil.appendWhere(selectStatement, "where username = 'user'");

                log.info("newSql:{}", newSql);

            } else if (statement instanceof Insert) {
                Insert insertStatement = (Insert) statement;
            } else if (statement instanceof Delete) {
                Delete deleteStatement = (Delete) statement;
            } else if (statement instanceof Update) {
                Update updateStatement = (Update) statement;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("sql替换后：{}", newSql);
        // 替换sql
        ExecutorPluginUtils.resetSqlToInvocation(invocation, newSql);

        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        properties.forEach((k,v)->{
            log.info("k:{},v:{}",k,v);
        });
        Interceptor.super.setProperties(properties);
    }
}
